home *** CD-ROM | disk | FTP | other *** search
/ Exame Informatica 139 / Exame Informatica 139.iso / Internet / NVU / chrome / toolkit.jar / content / mozapps / update / update.js < prev    next >
Encoding:
Text File  |  2004-11-05  |  38.3 KB  |  1,011 lines

  1. //
  2. // window.arguments[1...] is an array of nsIUpdateItem implementing objects 
  3. // that are to be updated. 
  4. //  * if the array is empty, all items are updated (like a background update
  5. //    check)
  6. //  * if the array contains one or two UpdateItems, with null id fields, 
  7. //    all items of that /type/ are updated.
  8. //
  9. // This UI can be opened from the following places, and in the following modes:
  10. //
  11. // - from the Version Compatibility Checker at startup
  12. //    as the application starts a check is done to see if the application being
  13. //    started is the same version that was started last time. If it isn't, a
  14. //    list of UpdateItems that are incompatible with the verison being 
  15. //    started is generated and this UI opened with that list. This UI then
  16. //    offers to check for updates to those UpdateItems that are compatible
  17. //    with the version of the application being started. 
  18. //    
  19. //    In this mode, the wizard is opened to panel 'mismatch'. 
  20. //
  21. // - from the Extension Manager or Options Dialog or any UI where the user
  22. //   directly requests to check for updates.
  23. //    in this case the user selects UpdateItem(s) to update and this list
  24. //    is passed to this UI. If a single item is sent with the id field set to
  25. //    null but the type set correctly, this UI will check for updates to all 
  26. //    items of that type.
  27. //
  28. //    In this mode, the wizard is opened to panel 'checking'.
  29. //
  30. // - from the Updates Available Status Bar notification.
  31. //    in this case the background update checking has determined there are new
  32. //    updates that can be installed and has prepared a list for the user to see.
  33. //    They can update by clicking on a status bar icon which passes the list
  34. //    to this UI which lets them choose to install updates. 
  35. //
  36. //    In this mode, the wizard is opened to panel 'updatesFound' if the data
  37. //    set is immediately available, or 'checking' if the user closed the browser
  38. //    since the last background check was performed and the check needs to be
  39. //    performed again. 
  40. //
  41.  
  42. const nsIUpdateItem       = Components.interfaces.nsIUpdateItem;
  43. const nsIUpdateService    = Components.interfaces.nsIUpdateService;
  44. const nsIExtensionManager = Components.interfaces.nsIExtensionManager;
  45.  
  46. const PREF_APP_ID                               = "app.id";
  47. const PREF_UPDATE_APP_UPDATESAVAILABLE          = "app.update.updatesAvailable";
  48. const PREF_UPDATE_APP_PERFORMED                 = "app.update.performed";
  49.  
  50. const PREF_UPDATE_EXTENSIONS_AUTOUPDATEENABLED  = "extensions.update.autoUpdateEnabled";
  51. const PREF_UPDATE_EXTENSIONS_COUNT              = "extensions.update.count";
  52. const PREF_UPDATE_EXTENSIONS_SEVERITY_THRESHOLD = "extensions.update.severity.threshold";
  53.  
  54. const PREF_UPDATE_SEVERITY                      = "update.severity";
  55.  
  56. var gSourceEvent = null;
  57. var gUpdateTypes = null;
  58.  
  59. var gUpdateWizard = {
  60.   // The items to check for updates for (e.g. an extension, some subset of extensions, 
  61.   // all extensions, a list of compatible extensions, etc...)
  62.   items: [],
  63.   // The items that we found updates available for
  64.   itemsToUpdate: [],
  65.   // The items that we successfully installed updates for
  66.   updatedCount: 0,
  67.   appUpdatesAvailable: false,
  68.  
  69.   shouldSuggestAutoChecking: false,
  70.   shouldAutoCheck: false,
  71.   
  72.   updatingApp: false,
  73.   remainingExtensionUpdateCount: 0,
  74.   
  75.   succeeded: true,
  76.   
  77.  
  78.   appComps: {
  79.     upgraded: { 
  80.       core      : [],
  81.       optional  : [],
  82.       languages : [],
  83.     },
  84.     optional: {
  85.       optional  : [],
  86.       languages : [],
  87.     }
  88.   },
  89.   selectedLocaleAvailable: false,
  90.  
  91.   init: function ()
  92.   {
  93.     gUpdateTypes = window.arguments[0];
  94.     gSourceEvent = window.arguments[1];
  95.     for (var i = 2; i < window.arguments.length; ++i)
  96.       this.items.push(window.arguments[i].QueryInterface(nsIUpdateItem));
  97.  
  98.     var pref = Components.classes["@mozilla.org/preferences-service;1"]
  99.                          .getService(Components.interfaces.nsIPrefBranch);
  100.     this.shouldSuggestAutoChecking = (gSourceEvent == nsIUpdateService.SOURCE_EVENT_MISMATCH) && 
  101.                                       !pref.getBoolPref(PREF_UPDATE_EXTENSIONS_AUTOUPDATEENABLED);
  102.  
  103.     if (gSourceEvent != nsIUpdateService.SOURCE_EVENT_MISMATCH)
  104.       document.documentElement.advance();
  105.     else 
  106.       gMismatchPage.init();
  107.   },
  108.   
  109.   uninit: function ()
  110.   {
  111.     // Ensure all observers are unhooked, just in case something goes wrong or the
  112.     // user aborts. 
  113.     gUpdatePage.uninit();  
  114.   },
  115.   
  116.   onWizardFinish: function ()
  117.   {
  118.     var pref = Components.classes["@mozilla.org/preferences-service;1"]
  119.                          .getService(Components.interfaces.nsIPrefBranch);
  120.     if (this.shouldSuggestAutoChecking)
  121.       pref.setBoolPref("update.extensions.enabled", this.shouldAutoCheck); 
  122.     
  123.     if (this.succeeded) {
  124.       if (this.updatingApp) {
  125.         // Clear the "app update available" pref as an interim amnesty assuming
  126.         // the user actually does install the new version. If they don't, a subsequent
  127.         // update check will poke them again.
  128.         this.clearAppUpdatePrefs();
  129.       }
  130.       else {
  131.         // Downloading and Installed Extension
  132.         this.clearExtensionUpdatePrefs();
  133.       }
  134.     }
  135.  
  136.     
  137.     // Send an event to refresh any FE notification components. 
  138.     var os = Components.classes["@mozilla.org/observer-service;1"]
  139.                        .getService(Components.interfaces.nsIObserverService);
  140.     var userEvt = Components.interfaces.nsIUpdateService.SOURCE_EVENT_USER;
  141.     os.notifyObservers(null, "Update:Ended", userEvt.toString());
  142.   },
  143.   
  144.   clearAppUpdatePrefs: function ()
  145.   {
  146.     var pref = Components.classes["@mozilla.org/preferences-service;1"]
  147.                          .getService(Components.interfaces.nsIPrefBranch);
  148.                          
  149.     // Set the "applied app updates this session" pref so that the update service
  150.     // does not display the update notifier for application updates anymore this
  151.     // session, to give the user a one-cycle amnesty to install the newer version.
  152.     var updates = Components.classes["@mozilla.org/updates/update-service;1"]
  153.                             .getService(Components.interfaces.nsIUpdateService);
  154.     updates.appUpdatesAvailable = false;
  155.     
  156.     pref.setBoolPref(PREF_UPDATE_APP_PERFORMED, true);    
  157.  
  158.     // Unset prefs used by the update service to signify application updates
  159.     if (pref.prefHasUserValue(PREF_UPDATE_APP_UPDATESAVAILABLE))
  160.       pref.clearUserPref(PREF_UPDATE_APP_UPDATESAVAILABLE);
  161.  
  162.     // Lower the severity to reflect the fact that there are now only Extension/
  163.     // Theme updates available
  164.     var newCount = pref.getIntPref(PREF_UPDATE_EXTENSIONS_COUNT);
  165.     var threshold = pref.getIntPref(PREF_UPDATE_EXTENSIONS_SEVERITY_THRESHOLD);
  166.     if (newCount >= threshold)
  167.       pref.setIntPref(PREF_UPDATE_SEVERITY, nsIUpdateService.SEVERITY_MEDIUM);
  168.     else
  169.       pref.setIntPref(PREF_UPDATE_SEVERITY, nsIUpdateService.SEVERITY_LOW);
  170.   },
  171.   
  172.   clearExtensionUpdatePrefs: function ()
  173.   {
  174.     var pref = Components.classes["@mozilla.org/preferences-service;1"]
  175.                          .getService(Components.interfaces.nsIPrefBranch);
  176.                          
  177.     // Set the "applied extension updates this session" pref so that the 
  178.     // update service does not display the update notifier for extension
  179.     // updates anymore this session (the updates will be applied at the next
  180.     // start).
  181.     var updates = Components.classes["@mozilla.org/updates/update-service;1"]
  182.                             .getService(Components.interfaces.nsIUpdateService);
  183.     updates.extensionUpdatesAvailable = this.remainingExtensionUpdateCount;
  184.     
  185.     if (pref.prefHasUserValue(PREF_UPDATE_EXTENSIONS_COUNT)) 
  186.       pref.clearUserPref(PREF_UPDATE_EXTENSIONS_COUNT);
  187.   },
  188.   
  189.   _setUpButton: function (aButtonID, aButtonKey, aDisabled)
  190.   {
  191.     var strings = document.getElementById("updateStrings");
  192.     var button = document.documentElement.getButton(aButtonID);
  193.     if (aButtonKey) {
  194.       button.label = strings.getString(aButtonKey);
  195.       try {
  196.         button.accesskey = strings.getString(aButtonKey + "Accesskey");
  197.       }
  198.       catch (e) {
  199.       }
  200.     }
  201.     button.disabled = aDisabled;
  202.   },
  203.   
  204.   setButtonLabels: function (aBackButton, aBackButtonIsDisabled, 
  205.                              aNextButton, aNextButtonIsDisabled,
  206.                              aCancelButton, aCancelButtonIsDisabled)
  207.   {
  208.     
  209.     this._setUpButton("back", aBackButton, aBackButtonIsDisabled);
  210.     this._setUpButton("next", aNextButton, aNextButtonIsDisabled);
  211.     this._setUpButton("cancel", aCancelButton, aCancelButtonIsDisabled);
  212.   },
  213.   
  214.   /////////////////////////////////////////////////////////////////////////////
  215.   // Update Errors
  216.   errorItems: [],
  217.   errorOnApp: false,
  218.  
  219.   showErrors: function (aState, aErrors)
  220.   {
  221.     openDialog("chrome://mozapps/content/update/errors.xul", "", 
  222.                "modal", { state: aState, errors: aErrors });
  223.   },
  224.   
  225.   showUpdateCheckErrors: function ()
  226.   {
  227.     var errors = [];
  228.     for (var i = 0; i < this.errorItems.length; ++i)
  229.       errors.push({ name: this.errorItems[i].name, error: true });
  230.  
  231.     if (this.errorOnApp) {
  232.       var brandShortName = document.getElementById("brandStrings").getString("brandShortName");
  233.       errors.push({ name: brandShortName, error: true });    
  234.     }
  235.     
  236.     this.showErrors("checking", errors);
  237.   },
  238.  
  239.   checkForErrors: function (aElementIDToShow)
  240.   {
  241.     if (this.errorOnGeneric || this.errorItems.length > 0 || this.errorOnApp)
  242.       document.getElementById(aElementIDToShow).hidden = false;
  243.   },
  244.   
  245.   onWizardClose: function (aEvent)
  246.   {
  247.     if (gInstallingPage._installing) {
  248.       var os = Components.classes["@mozilla.org/observer-service;1"]
  249.                         .getService(Components.interfaces.nsIObserverService);
  250.       os.notifyObservers(null, "xpinstall-progress", "cancel");
  251.       return false;
  252.     }    
  253.     return true;
  254.   }
  255. };
  256.  
  257. var gMismatchPage = {
  258.   init: function ()
  259.   {
  260.     var incompatible = document.getElementById("mismatch.incompatible");
  261.     for (var i = 0; i < gUpdateWizard.items.length; ++i) {
  262.       var item = gUpdateWizard.items[i];
  263.       var listitem = document.createElement("listitem");
  264.       listitem.setAttribute("label", item.name + " " + item.version);
  265.       incompatible.appendChild(listitem);
  266.     }
  267.   },
  268.   
  269.   onPageShow: function ()
  270.   {
  271.     gUpdateWizard.setButtonLabels(null, true, 
  272.                                   "mismatchCheckNow", false, 
  273.                                   "mismatchDontCheck", false);
  274.     document.documentElement.getButton("next").focus();
  275.   }
  276. };
  277.  
  278. var gUpdatePage = {
  279.   _completeCount: 0,
  280.   _messages: ["Update:Extension:Started", 
  281.               "Update:Extension:Ended", 
  282.               "Update:Extension:Item-Started", 
  283.               "Update:Extension:Item-Ended",
  284.               "Update:Extension:Item-Error",
  285.               "Update:App:Ended",
  286.               "Update:Ended"],
  287.   
  288.   onPageShow: function ()
  289.   {
  290.     gUpdateWizard.setButtonLabels(null, true, 
  291.                                   "nextButtonText", true, 
  292.                                   "cancelButtonText", false);
  293.     document.documentElement.getButton("next").focus();
  294.  
  295.     var os = Components.classes["@mozilla.org/observer-service;1"]
  296.                        .getService(Components.interfaces.nsIObserverService);
  297.     for (var i = 0; i < this._messages.length; ++i)
  298.       os.addObserver(this, this._messages[i], false);
  299.  
  300.     gUpdateWizard.errorItems = [];
  301.  
  302.     var updates = Components.classes["@mozilla.org/updates/update-service;1"]
  303.                             .getService(Components.interfaces.nsIUpdateService);
  304.     updates.checkForUpdatesInternal(gUpdateWizard.items, gUpdateWizard.items.length, 
  305.                                     gUpdateTypes, gSourceEvent);
  306.   },
  307.  
  308.   _destroyed: false,  
  309.   uninit: function ()
  310.   {
  311.     if (this._destroyed)
  312.       return;
  313.   
  314.     var os = Components.classes["@mozilla.org/observer-service;1"]
  315.                        .getService(Components.interfaces.nsIObserverService);
  316.     for (var i = 0; i < this._messages.length; ++i)
  317.       os.removeObserver(this, this._messages[i]);
  318.  
  319.     this._destroyed = true;
  320.   },
  321.  
  322.   _totalCount: 0,
  323.   get totalCount()
  324.   {
  325.     if (!this._totalCount) {
  326.       this._totalCount = gUpdateWizard.items.length;
  327.       if (this._totalCount == 0) {
  328.         var em = Components.classes["@mozilla.org/extensions/manager;1"]
  329.                             .getService(Components.interfaces.nsIExtensionManager);
  330.         var extensionCount = em.getItemList(null, nsIUpdateItem.TYPE_EXTENSION, {}).length;
  331.         var themeCount = em.getItemList(null, nsIUpdateItem.TYPE_THEME, {}).length;
  332.  
  333.         this._totalCount = extensionCount + themeCount + 1;
  334.       }
  335.     }
  336.     return this._totalCount;
  337.   },  
  338.   
  339.   observe: function (aSubject, aTopic, aData)
  340.   {
  341.     var canFinish = false;
  342.     switch (aTopic) {
  343.     case "Update:Extension:Started":
  344.       break;
  345.     case "Update:Extension:Item-Started":
  346.       break;
  347.     case "Update:Extension:Item-Ended":
  348.       if (aSubject) {
  349.         var item = aSubject.QueryInterface(Components.interfaces.nsIUpdateItem);
  350.         gUpdateWizard.itemsToUpdate.push(item);
  351.       
  352.         var updateStrings = document.getElementById("updateStrings");
  353.         var status = document.getElementById("checking.status");
  354.         var statusString = updateStrings.getFormattedString("checkingPrefix", [item.name]);
  355.         status.setAttribute("value", statusString);
  356.       }
  357.       ++this._completeCount;
  358.  
  359.       // Update the Progress Bar            
  360.       var progress = document.getElementById("checking.progress");
  361.       progress.value = Math.ceil((this._completeCount / this.totalCount) * 100);
  362.       
  363.       break;
  364.     case "Update:Extension:Item-Error":
  365.       if (aSubject) {
  366.         var item = aSubject.QueryInterface(Components.interfaces.nsIUpdateItem);
  367.         gUpdateWizard.errorItems.push(item);
  368.       }
  369.       else {
  370.         for (var i = 0; i < gUpdateWizard.items.length; ++i) {
  371.           if (!gUpdateWizard.items[i].updateRDF)
  372.             gUpdateWizard.errorItems.push(gUpdateWizard.items[i]);
  373.         }
  374.       }
  375.       ++this._completeCount;
  376.       var progress = document.getElementById("checking.progress");
  377.       progress.value = Math.ceil((this._completeCount / this.totalCount) * 100);
  378.  
  379.       break;
  380.     case "Update:Extension:Ended":
  381.       // If we were passed a set of extensions/themes/other to update, this
  382.       // means we're not checking for app updates, so don't wait for the app
  383.       // update to complete before advancing (because there is none).
  384.       // canFinish = gUpdateWizard.items.length > 0;
  385.       // XXXben
  386.       break;
  387.     case "Update:Ended":
  388.       // If we're doing a general update check, (that is, no specific extensions/themes
  389.       // were passed in for us to check for updates to), this notification means both
  390.       // extension and app updates have completed.
  391.       canFinish = true;
  392.       break;
  393.     case "Update:App:Error":
  394.       gUpdateWizard.errorOnApp = true;
  395.       ++this._completeCount;
  396.       var progress = document.getElementById("checking.progress");
  397.       progress.value = Math.ceil((this._completeCount / this.totalCount) * 100);
  398.       break;
  399.     case "Update:App:Ended":
  400.       // The "Updates Found" page of the update wizard needs to know if it there are app 
  401.       // updates so it can list them first. 
  402.       ++this._completeCount;
  403.       var progress = document.getElementById("checking.progress");
  404.       progress.value = Math.ceil((this._completeCount / this.totalCount) * 100);
  405.       break;
  406.     }
  407.  
  408.     if (canFinish) {
  409.       gUpdatePage.uninit();
  410.       var updates = Components.classes["@mozilla.org/updates/update-service;1"]
  411.                               .getService(Components.interfaces.nsIUpdateService);
  412.       if ((gUpdateTypes & nsIUpdateItem.TYPE_ADDON && gUpdateWizard.itemsToUpdate.length > 0) || 
  413.           (gUpdateTypes & nsIUpdateItem.TYPE_APP && updates.appUpdatesAvailable))
  414.         document.getElementById("checking").setAttribute("next", "found");
  415.       document.documentElement.advance();
  416.     }
  417.   }
  418. };
  419.  
  420. var gFoundPage = {
  421.   _appUpdateExists: false,
  422.   _appSelected: false, 
  423.   _appItem: null,
  424.   _nonAppItems: [],
  425.   
  426.   _newestInfo: null,
  427.   _currentInfo: null,
  428.   
  429.   buildAddons: function ()
  430.   {
  431.     var hasExtensions = false;
  432.     var foundAddonsList = document.getElementById("found.addons.list");
  433.     var uri = Components.classes["@mozilla.org/network/standard-url;1"]
  434.                         .createInstance(Components.interfaces.nsIURI);
  435.     var itemCount = gUpdateWizard.itemsToUpdate.length;
  436.     for (var i = 0; i < itemCount; ++i) {
  437.       var item = gUpdateWizard.itemsToUpdate[i];
  438.       var checkbox = document.createElement("checkbox");
  439.       foundAddonsList.appendChild(checkbox);
  440.       checkbox.setAttribute("type", "update");
  441.       checkbox.label        = item.name + " " + item.version;
  442.       checkbox.URL          = item.xpiURL;
  443.       checkbox.infoURL      = "";
  444.       checkbox.internalName = "";
  445.       uri.spec              = item.xpiURL;
  446.       checkbox.source       = uri.host;
  447.       checkbox.checked      = true;
  448.       hasExtensions         = true;
  449.     }
  450.  
  451.     if (hasExtensions) {
  452.       var addonsHeader = document.getElementById("addons");
  453.       var strings = document.getElementById("updateStrings");
  454.       addonsHeader.label = strings.getFormattedString("updateTypeExtensions", [itemCount]);
  455.       addonsHeader.collapsed = false;
  456.     }
  457.   },
  458.  
  459.   buildPatches: function (aPatches)
  460.   {
  461.     var needsPatching = false;
  462.     var critical = document.getElementById("found.criticalUpdates.list");
  463.     var uri = Components.classes["@mozilla.org/network/standard-url;1"]
  464.                         .createInstance(Components.interfaces.nsIURI);
  465.     var count = 0;
  466.     for (var i = 0; i < aPatches.length; ++i) {
  467.       var ver = InstallTrigger.getVersion(aPatches[i].internalName);
  468.       if (InstallTrigger.getVersion(aPatches[i].internalName)) {
  469.         // The user has already installed this patch since info
  470.         // about it exists in the Version Registry. Skip. 
  471.         continue;
  472.       }
  473.       
  474.       var checkbox = document.createElement("checkbox");
  475.       critical.appendChild(checkbox);
  476.       checkbox.setAttribute("type", "update");
  477.       checkbox.label        = aPatches[i].name;
  478.       checkbox.URL          = aPatches[i].URL;
  479.       checkbox.infoURL      = aPatches[i].infoURL;
  480.       checkbox.internalName = aPatches[i].internalName;
  481.       uri.spec              = checkbox.URL;
  482.       checkbox.source       = uri.host;
  483.       checkbox.checked      = true;
  484.       needsPatching         = true;
  485.       ++count;
  486.     }
  487.     
  488.     if (needsPatching) {
  489.       var patchesHeader = document.getElementById("patches");
  490.       var strings = document.getElementById("updateStrings");
  491.       patchesHeader.label = strings.getFormattedString("updateTypePatches", [count]);
  492.       patchesHeader.collapsed = false;
  493.     }
  494.   },
  495.   
  496.   buildApp: function (aFiles)
  497.   {
  498.     // A New version of the app is available. 
  499.     var app = document.getElementById("app");
  500.     var strings = document.getElementById("updateStrings");
  501.     var brandStrings = document.getElementById("brandStrings");
  502.     var brandShortName = brandStrings.getString("brandShortName");
  503.     app.label = strings.getFormattedString("appNameAndVersionFormat", 
  504.                                             [brandShortName, 
  505.                                              this._newestInfo.updateDisplayVersion]);
  506.     app.accesskey = brandShortName.charAt(0);
  507.     app.collapsed = false;
  508.  
  509.     var foundAppLabel = document.getElementById("found.app.label");
  510.     var text = strings.getFormattedString("foundAppLabel",
  511.                                           [brandShortName, 
  512.                                            this._newestInfo.updateDisplayVersion])
  513.     foundAppLabel.appendChild(document.createTextNode(text));
  514.  
  515.     var features = this._newestInfo.getCollection("features", { });
  516.     if (features) {
  517.       var foundAppFeatures = document.getElementById("found.app.features");
  518.       foundAppFeatures.hidden = false;
  519.       text = strings.getFormattedString("foundAppFeatures", 
  520.                                         [brandShortName, 
  521.                                          this._newestInfo.updateDisplayVersion]);
  522.       foundAppFeatures.appendChild(document.createTextNode(text));
  523.  
  524.       var foundAppFeaturesList = document.getElementById("found.app.featuresList");
  525.       for (var i = 0; i < features.length; ++i) {
  526.         var feature = document.createElement("label");
  527.         foundAppFeaturesList.appendChild(feature);
  528.         feature.setAttribute("value", features[i].name);
  529.       }
  530.     }
  531.     
  532.     var foundAppInfoLink = document.getElementById("found.app.infoLink");
  533.     foundAppInfoLink.href = this._newestInfo.updateInfoURL;
  534.   },
  535.   
  536.   buildOptional: function (aComponents)
  537.   {
  538.     var needsOptional = false;
  539.     var critical = document.getElementById("found.components.list");
  540.     var uri = Components.classes["@mozilla.org/network/standard-url;1"]
  541.                         .createInstance(Components.interfaces.nsIURI);
  542.     var count = 0;
  543.     for (var i = 0; i < aComponents.length; ++i) {
  544.       if (InstallTrigger.getVersion(aComponents[i].internalName)) {
  545.         // The user has already installed this patch since info
  546.         // about it exists in the Version Registry. Skip. 
  547.         continue;
  548.       }
  549.       
  550.       var checkbox = document.createElement("checkbox");
  551.       critical.appendChild(checkbox);
  552.       checkbox.setAttribute("type", "update");
  553.       checkbox.label        = aComponents[i].name;
  554.       checkbox.URL          = aComponents[i].URL;
  555.       checkbox.infoURL      = aComponents[i].infoURL;
  556.       checkbox.internalName = aComponents[i].internalName;
  557.       uri.spec              = checkbox.URL;
  558.       checkbox.source       = uri.host;
  559.       needsOptional         = true;
  560.       ++count;
  561.     }
  562.     
  563.     if (needsOptional) {
  564.       var optionalHeader = document.getElementById("components");
  565.       var strings = document.getElementById("updateStrings");
  566.       optionalHeader.label = strings.getFormattedString("updateTypeComponents", [count]);
  567.       optionalHeader.collapsed = false;
  568.     }
  569.   },
  570.  
  571.   buildLanguages: function (aLanguages)
  572.   {
  573.     var hasLanguages = false;
  574.     var languageList = document.getElementById("found.languages.list");
  575.     var uri = Components.classes["@mozilla.org/network/standard-url;1"]
  576.                         .createInstance(Components.interfaces.nsIURI);
  577.     var cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
  578.                        .getService(Components.interfaces.nsIXULChromeRegistry);
  579.     var selectedLocale = cr.getSelectedLocale("global");
  580.     var count = 0;
  581.     for (var i = 0; i < aLanguages.length; ++i) {
  582.       if (aLanguages[i].internalName == selectedLocale)
  583.         continue;
  584.       var checkbox = document.createElement("checkbox");
  585.       languageList.appendChild(checkbox);
  586.       checkbox.setAttribute("type", "update");
  587.       checkbox.label        = aLanguages[i].name;
  588.       checkbox.URL          = aLanguages[i].URL;
  589.       checkbox.infoURL      = aLanguages[i].infoURL;
  590.       checkbox.internalName = aLanguages[i].internalName;
  591.       uri.spec              = checkbox.URL;
  592.       checkbox.source       = uri.host;
  593.       hasLanguages          = true;
  594.       ++count;
  595.     }
  596.     
  597.     if (hasLanguages) {
  598.       var languagesHeader = document.getElementById("found.languages.header");
  599.       var strings = document.getElementById("updateStrings");
  600.       languagesHeader.label = strings.getFormattedString("updateTypeLangPacks", [count]);
  601.       languagesHeader.collapsed = false;
  602.     }
  603.   },
  604.  
  605.   _initialized: false,
  606.   onPageShow: function ()
  607.   {
  608.     gUpdateWizard.setButtonLabels(null, true, 
  609.                                   "installButtonText", false, 
  610.                                   null, false);
  611.     document.documentElement.getButton("next").focus();
  612.     
  613.     var updates = document.getElementById("found.updates");
  614.     if (!this._initialized) {
  615.       this._initialized = true;
  616.       
  617.       updates.computeSizes();
  618.  
  619.       // Don't show the app update option or critical updates if the user has 
  620.       // already installed an app update but has not yet restarted. 
  621.       var pref = Components.classes["@mozilla.org/preferences-service;1"]
  622.                           .getService(Components.interfaces.nsIPrefBranch);
  623.       var updatePerformed = pref.getBoolPref(PREF_UPDATE_APP_PERFORMED);
  624.       if (gUpdateTypes & nsIUpdateItem.TYPE_APP) {
  625.         var updatesvc = Components.classes["@mozilla.org/updates/update-service;1"]
  626.                                   .getService(Components.interfaces.nsIUpdateService);
  627.         this._currentInfo = updatesvc.currentVersion;
  628.         if (this._currentInfo) {
  629.           var patches = this._currentInfo.getCollection("patches", { });
  630.           if (patches.length > 0 && !updatePerformed)
  631.             this.buildPatches(patches);
  632.  
  633.           // Turning this off until we can better determine what is and is not installed. 
  634.           // var components = this._currentInfo.getCollection("optional", { });
  635.           // if (components.length > 0)
  636.           //   this.buildOptional(components);
  637.  
  638.           var languages = this._currentInfo.getCollection("languages", { });
  639.           if (languages.length > 0)
  640.             this.buildLanguages(languages);
  641.         }
  642.         
  643.         this._newestInfo = updatesvc.newestVersion;
  644.         if (this._newestInfo) {
  645.           var languages = this._newestInfo.getCollection("languages", { });
  646.           var cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
  647.                             .getService(Components.interfaces.nsIXULChromeRegistry);
  648.           var selectedLocale = cr.getSelectedLocale("global");
  649.           var haveLanguage = false;
  650.           for (var i = 0; i < languages.length; ++i) {
  651.             if (languages[i].internalName == selectedLocale)
  652.               haveLanguage = true;
  653.           }
  654.  
  655.           var files = this._newestInfo.getCollection("files", { });
  656.           if (files.length > 0 && haveLanguage && !updatePerformed) 
  657.             this.buildApp(files);
  658.             
  659.           // When the user upgrades the application, any optional components that
  660.           // they have installed are automatically installed. If there are remaining
  661.           // optional components that are not currently installed, then these
  662.           // are offered as an option.
  663.           var components = this._newestInfo.getCollection("optional", { });
  664.           for (var i = 0; i < components.length; ++i) {
  665.             if (InstallTrigger.getVersion(components[i].internalName))
  666.               gUpdateWizard.appComps.upgraded.optional.push(components[i]);
  667.             else
  668.               gUpdateWizard.appComps.optional.optional.push(components[i]);
  669.           }
  670.           
  671.           var cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
  672.                             .getService(Components.interfaces.nsIXULChromeRegistry);
  673.           var selectedLocale = cr.getSelectedLocale("global");
  674.           gUpdateWizard.selectedLocaleAvailable = false;
  675.           var languages = this._newestInfo.getCollection("languages", { });
  676.           for (i = 0; i < languages.length; ++i) {
  677.             if (languages[i].internalName == selectedLocale) {
  678.               gUpdateWizard.selectedLocaleAvailable = true;
  679.               gUpdateWizard.appComps.upgraded.languages.push(languages[i]);
  680.             }
  681.           }
  682.           
  683.           if (!gUpdateWizard.selectedLocaleAvailable)
  684.             gUpdateWizard.appComps.optional.languages = gUpdateWizard.appComps.optional.languages.concat(languages);
  685.             
  686.           gUpdateWizard.appComps.upgraded.core = gUpdateWizard.appComps.upgraded.core.concat(files);
  687.         }
  688.       }
  689.  
  690.       if (gUpdateTypes & nsIUpdateItem.TYPE_ADDON)
  691.         this.buildAddons();
  692.     }
  693.         
  694.     var kids = updates._getRadioChildren();
  695.     for (var i = 0; i < kids.length; ++i) {
  696.       if (kids[i].collapsed == false) {
  697.         updates.selectedIndex = i;
  698.         break;
  699.       }
  700.     }
  701.   },
  702.     
  703.   onSelect: function (aEvent)
  704.   {
  705.     var updates = document.getElementById("found.updates");
  706.     var oneChecked = true;
  707.     if (updates.selectedItem.id != "app") {
  708.       oneChecked = false;
  709.       var items = updates.selectedItem.getElementsByTagName("checkbox");
  710.       for (var i = 0; i < items.length; ++i) {  
  711.         if (items[i].checked) {
  712.           oneChecked = true;
  713.           break;
  714.         }
  715.       }
  716.     }
  717.  
  718.     var strings = document.getElementById("updateStrings");
  719.     var text;
  720.     if (aEvent.target.selectedItem.id == "app") {
  721.       if (gUpdateWizard.appComps.optional.optional.length > 0) {
  722.         gUpdateWizard.setButtonLabels(null, true, 
  723.                                       "nextButtonText", true, 
  724.                                       null, false);
  725.           
  726.         text = strings.getString("foundInstructionsAppComps");
  727.         document.getElementById("found").setAttribute("next", "optional"); 
  728.       }
  729.       gUpdateWizard.updatingApp = true;
  730.     }
  731.     else {
  732.       gUpdateWizard.setButtonLabels(null, true, 
  733.                                     "installButtonText", true, 
  734.                                     null, false);
  735.       text = strings.getString("foundInstructions");
  736.       document.getElementById("found").setAttribute("next", "installing"); 
  737.       
  738.       gUpdateWizard.updatingApp = false;
  739.     }
  740.         
  741.     document.documentElement.getButton("next").disabled = !oneChecked;
  742.  
  743.     var foundInstructions = document.getElementById("foundInstructions");
  744.     while (foundInstructions.hasChildNodes())
  745.       foundInstructions.removeChild(foundInstructions.firstChild);
  746.     foundInstructions.appendChild(document.createTextNode(text));
  747.   }
  748. };
  749.  
  750. var gOptionalPage = {
  751.   onPageShow: function ()
  752.   {
  753.     gUpdateWizard.setButtonLabels(null, false, 
  754.                                   "installButtonText", false, 
  755.                                   null, false);
  756.  
  757.     var optionalItemsList = document.getElementById("optionalItemsList");
  758.     while (optionalItemsList.hasChildNodes())
  759.       optionalItemsList.removeChild(optionalItemsList.firstChild);
  760.  
  761.     for (var i = 0; i < gUpdateWizard.appComps.optional.optional.length; ++i) {
  762.       var checkbox = document.createElement("checkbox");
  763.       checkbox.setAttribute("label", gUpdateWizard.appComps.optional.optional[i].name);
  764.       checkbox.setAttribute("index", i);
  765.       optionalItemsList.appendChild(checkbox);
  766.     }
  767.     
  768.     document.documentElement.getButton("next").focus(); 
  769.   },
  770.   
  771.   onCommand: function (aEvent)
  772.   {
  773.     if (aEvent.target.localName == "checkbox") {
  774.       gUpdateWizard.appComps.upgraded.optional = [];
  775.       var optionalItemsList = document.getElementById("optionalItemsList");
  776.       var checkboxes = optionalItemsList.getElementsByTagName("checkbox");
  777.       for (var i = 0; i < checkboxes.length; ++i) {
  778.         if (checkboxes[i].checked) {
  779.           var index = parseInt(checkboxes[i].getAttribute("index"));
  780.           var item = gUpdateWizard.appComps.optional.optional[index];
  781.           gUpdateWizard.appComps.upgraded.optional.push(item);
  782.         }
  783.       }
  784.     }
  785.   },
  786.   
  787.   onListMouseOver: function (aEvent)
  788.   {
  789.     if (aEvent.target.localName == "checkbox") {
  790.       var index = parseInt(aEvent.target.getAttribute("index"));
  791.       var desc = gUpdateWizard.appComps.optional.optional[index].description;
  792.       var optionalDescription = document.getElementById("optionalDescription");
  793.       while (optionalDescription.hasChildNodes()) 
  794.         optionalDescription.removeChild(optionalDescription.firstChild);
  795.       optionalDescription.appendChild(document.createTextNode(desc));
  796.     }
  797.   },
  798.   
  799.   onListMouseOut: function (aEvent)
  800.   {
  801.     if (aEvent.target.localName == "vbox") {
  802.       var optionalDescription = document.getElementById("optionalDescription");
  803.       while (optionalDescription.hasChildNodes()) 
  804.         optionalDescription.removeChild(optionalDescription.firstChild);
  805.     }
  806.   }
  807. };
  808.  
  809. var gInstallingPage = {
  810.   _installing       : false,
  811.   _restartRequired  : false,
  812.   _objs             : [],
  813.   
  814.   onPageShow: function ()
  815.   {
  816.     gUpdateWizard.setButtonLabels(null, true, 
  817.                                   "nextButtonText", true, 
  818.                                   null, true);
  819.  
  820.     // Get XPInstallManager and kick off download/install 
  821.     // process, registering us as an observer. 
  822.     var items = [];
  823.     this._objs = [];
  824.     
  825.     this._restartRequired = false;
  826.     
  827.     gUpdateWizard.remainingExtensionUpdateCount = gUpdateWizard.itemsToUpdate.length;
  828.  
  829.     var updates = document.getElementById("found.updates");
  830.     if (updates.selectedItem.id != "app") {
  831.       var checkboxes = updates.selectedItem.getElementsByTagName("checkbox");
  832.       for (var i = 0; i < checkboxes.length; ++i) {
  833.         if (checkboxes[i].type == "update" && checkboxes[i].checked) {
  834.           items.push(checkboxes[i].URL);
  835.           this._objs.push({ name: checkboxes[i].label });
  836.         }
  837.       }
  838.     }
  839.     else {
  840.       // To install an app update we need to collect together the following
  841.       // sets of files:
  842.       // - core files
  843.       // - optional components (we need to show another page) 
  844.       // - selected language, if the available language set does not match
  845.       //   the one currently selected for the "global" package
  846.       // Order is *probably* important here.      
  847.       for (var i = 0; i < gUpdateWizard.appComps.upgraded.core.length; ++i) {
  848.         items.push(gUpdateWizard.appComps.upgraded.core[i].URL);
  849.         this._objs.push({ name: gUpdateWizard.appComps.upgraded.core[i].name });
  850.       }
  851.       for (var i = 0; i < gUpdateWizard.appComps.upgraded.languages.length; ++i) {
  852.         items.push(gUpdateWizard.appComps.upgraded.languages[i].URL);
  853.         this._objs.push({ name: gUpdateWizard.appComps.upgraded.languages[i].name });
  854.       }
  855.       for (var i = 0; i < gUpdateWizard.appComps.upgraded.optional.length; ++i) {
  856.         items.push(gUpdateWizard.appComps.upgraded.optional[i].URL);
  857.         this._objs.push({ name: gUpdateWizard.appComps.upgraded.optional[i].name });
  858.       }
  859.     }
  860.     
  861.     var xpimgr = Components.classes["@mozilla.org/xpinstall/install-manager;1"]
  862.                            .createInstance(Components.interfaces.nsIXPInstallManager);
  863.     xpimgr.initManagerFromChrome(items, items.length, this);
  864.   },
  865.   
  866.   /////////////////////////////////////////////////////////////////////////////
  867.   // nsIXPIProgressDialog
  868.   onStateChange: function (aIndex, aState, aValue)
  869.   {
  870.     var strings = document.getElementById("updateStrings");
  871.  
  872.     const nsIXPIProgressDialog = Components.interfaces.nsIXPIProgressDialog;
  873.     switch (aState) {
  874.     case nsIXPIProgressDialog.DOWNLOAD_START:
  875.       var label = strings.getFormattedString("downloadingPrefix", [this._objs[aIndex].name]);
  876.       var actionItem = document.getElementById("actionItem");
  877.       actionItem.value = label;
  878.       break;
  879.     case nsIXPIProgressDialog.DOWNLOAD_DONE:
  880.     case nsIXPIProgressDialog.INSTALL_START:
  881.       var label = strings.getFormattedString("installingPrefix", [this._objs[aIndex].name]);
  882.       var actionItem = document.getElementById("actionItem");
  883.       actionItem.value = label;
  884.       this._installing = true;
  885.       break;
  886.     case nsIXPIProgressDialog.INSTALL_DONE:
  887.       switch (aValue) {
  888.       case 999: 
  889.         this._restartRequired = true;
  890.         break;
  891.       case 0: 
  892.         --gUpdateWizard.remainingExtensionUpdateCount;
  893.         break;
  894.       default:
  895.         // XXXben ignore chrome registration errors hack!
  896.         if (!(aValue == -239 && gUpdateWizard.updatingApp)) {
  897.           this._objs[aIndex].error = aValue;
  898.           this._errors = true;
  899.         }
  900.         break;
  901.       }
  902.       break;
  903.     case nsIXPIProgressDialog.DIALOG_CLOSE:
  904.       this._installing = false;
  905.       var nextPage = this._errors ? "errors" : (this._restartRequired ? "restart" : "finished");
  906.       document.getElementById("installing").setAttribute("next", nextPage);
  907.       document.documentElement.advance();
  908.       break;
  909.     }
  910.   },
  911.   
  912.   _objs: [],
  913.   _errors: false,
  914.   
  915.   onProgress: function (aIndex, aValue, aMaxValue)
  916.   {
  917.     var downloadProgress = document.getElementById("downloadProgress");
  918.     downloadProgress.value = Math.ceil((aValue/aMaxValue) * 100);
  919.   }
  920. };
  921.  
  922. var gErrorsPage = {
  923.   onPageShow: function ()
  924.   {
  925.     document.documentElement.getButton("finish").focus();
  926.     gUpdateWizard.succeeded = false;
  927.   },
  928.   
  929.   onShowErrors: function ()
  930.   {
  931.     gUpdateWizard.showErrors("install", gInstallingPage._objs);
  932.   }  
  933. };
  934.  
  935. var gFinishedPage = {
  936.   onPageShow: function ()
  937.   {
  938.     gUpdateWizard.setButtonLabels(null, true, null, true, null, true);
  939.     document.documentElement.getButton("finish").focus();
  940.     
  941.     var iR = document.getElementById("incompatibleRemaining");
  942.     var iR2 = document.getElementById("incompatibleRemaining2");
  943.     var fEC = document.getElementById("finishedEnableChecking");
  944.  
  945.     if (gUpdateWizard.shouldSuggestAutoChecking) {
  946.       iR.hidden = true;
  947.       iR2.hidden = false;
  948.       fEC.hidden = false;
  949.       fEC.click();
  950.     }
  951.     else {
  952.       iR.hidden = false;
  953.       iR2.hidden = true;
  954.       fEC.hidden = true;
  955.     }
  956.     
  957.     if (gSourceEvent == nsIUpdateService.SOURCE_EVENT_MISMATCH) {
  958.       document.getElementById("finishedMismatch").hidden = false;
  959.       document.getElementById("incompatibleAlert").hidden = false;
  960.     }
  961.   }
  962. };
  963.  
  964. var gRestartPage = {
  965.   onPageShow: function ()
  966.   {
  967.     gUpdateWizard.setButtonLabels(null, true, null, true, null, true);
  968.     
  969.     // XXXben - we should really have a way to restart the app now from here!
  970.     
  971.  
  972.     document.documentElement.getButton("finish").focus();
  973.  
  974.     // Create a re-reg chrome marker to tell the Chrome Registry to rebuild the
  975.     // Chrome Reg Datasource and overlayinfo directory on the next start since 
  976.     // we've upgraded in-place (and thus chrome.rdf's mtime is newer than the
  977.     // installed-chrome.txt file that was installed by the update process since
  978.     // chrome.rdf was flushed when the browser started, AFTER installed-chrome.txt
  979.     // was created.
  980.     var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"]
  981.                                 .getService(Components.interfaces.nsIProperties);
  982.     var file = fileLocator.get("AChrom", Components.interfaces.nsIFile);
  983.     file.append(".reregchrome");
  984.     if (!file.exists())
  985.       file.create(Components.interfaces.nsIFile.FILE_TYPE, 0644);
  986.   }
  987. };
  988.  
  989. var gNoUpdatesPage = {
  990.   onPageShow: function (aEvent)
  991.   {
  992.     gUpdateWizard.setButtonLabels(null, true, null, true, null, true);
  993.     document.documentElement.getButton("finish").focus();
  994.     if (gSourceEvent == nsIUpdateService.SOURCE_EVENT_MISMATCH) {
  995.       document.getElementById("introUser").hidden = true;
  996.       document.getElementById("introMismatch").hidden = false;
  997.       document.getElementById("mismatchNoUpdates").hidden = false;
  998.         
  999.       if (gUpdateWizard.shouldSuggestAutoChecking) {
  1000.         document.getElementById("mismatchIncompatibleRemaining").hidden = true;
  1001.         document.getElementById("mismatchIncompatibleRemaining2").hidden = false;
  1002.         document.getElementById("mismatchFinishedEnableChecking").hidden = false;
  1003.       }
  1004.     }
  1005.  
  1006.     gUpdateWizard.succeeded = false;
  1007.     gUpdateWizard.checkForErrors("updateCheckErrorNotFound");
  1008.   }
  1009. };
  1010.  
  1011.